package model

import (
	"fmt"

	"gorm.io/gorm"
)

func FindMediaByID(db *gorm.DB, id uint) (*Media, error) {
	var ret Media
	if err := db.Preload("Labels").Take(&ret, id).Error; err != nil {
		return nil, err
	}
	return &ret, nil
}

const (
	MEDIA_STAGE_PENDING = "pending"
	MEDIA_STAGE_WORKING = "working"
	MEDIA_STAGE_CONFIRM = "confirm"
)

func IsValidMediaStage(stage string) bool {
	switch stage {
	case MEDIA_STAGE_PENDING:
		return true
	case MEDIA_STAGE_WORKING:
		return true
	case MEDIA_STAGE_CONFIRM:
		return true
	default:
		return false
	}
}

type ExtendMedia struct {
	Media
	Status string `json:"status"`
}

func ListAllMedia(db *gorm.DB, stage string) ([]ExtendMedia, error) {
	ret := []ExtendMedia{}

	builder := db.Table("media").Joins("left join selections on media.selection_id = selections.id")

	if stage != "" && !IsValidMediaStage(stage) {
		return nil, fmt.Errorf("invalid stage: %s", stage)
	}

	if stage == MEDIA_STAGE_PENDING {
		subQuery := db.Table("labels").Distinct("media_id")
		builder = builder.Where("media.id NOT IN (?)", subQuery)
	}

	if stage == MEDIA_STAGE_CONFIRM {
		subQuery := db.Table("labels").Distinct("media_id").Where("status = ?", LABEL_CONFIRM)
		builder = builder.Where("media.id IN (?)", subQuery)
	}

	if stage == MEDIA_STAGE_WORKING {
		subQuery1 := db.Table("labels").Distinct("media_id")
		subQuery2 := db.Table("labels").Distinct("media_id").Where("status = ?", LABEL_CONFIRM)
		builder = builder.Where("media.id IN (?)", subQuery1).Where("media.id NOT IN (?)", subQuery2)
	}

	res := builder.Select("media.*, selections.status").Scan(&ret)

	if err := res.Error; err != nil {
		return nil, err
	}
	return ret, nil
}

func ListMediaLabel(db *gorm.DB, id uint, status string, author *uint64) ([]Label, error) {
	var ret []Label
	builder := db.Where("media_id = ?", id)
	if status != "" {
		builder = builder.Where("status = ?", status)
	}

	if author != nil {
		builder = builder.Where("author_id = ?", *author)
	}

	if err := builder.Find(&ret).Error; err != nil {
		return nil, err
	}

	return ret, nil
}
